package com.fairy.sso.client.filter;

import java.io.IOException;
import java.net.InetAddress;
import java.util.ResourceBundle;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;

import com.fairy.sso.client.Factory;
import com.fairy.sso.client.SSOSessionFactory;
import com.fairy.sso.client.session.SSOSession;
import com.fairy.sso.core.HttpUtil;
import com.fairy.sso.core.NetClientHelp;
import com.fairy.sso.core.NetHelp;
import com.fairy.sso.core.SSOConstants;

public class SSOClientFilter implements Filter {
	private Logger log = Logger.getLogger(SSOClientFilter.class);
    @Override
    public void destroy() {
    }

	@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpSession httpSession = request.getSession();

        InetAddress addr = InetAddress.getLocalHost();

        String sso_use=SSOClientFilterHelp.getConfigUrl("sso_use");
        if(null!=sso_use&&sso_use.equals("true"))
        {
        	SSOClientFilterHelp.trace(log, "=====================单点登录启用=====================");
            String sso_sync_ticket_url=SSOClientFilterHelp.getConfigUrl("sso.sync.ticket.url");
            String  picture_format=SSOClientFilterHelp.getProperty("picture_format");
            String  sso_client_login_local=SSOClientFilterHelp.getProperty("sso_client_login_local");
            String  sessionType=SSOClientFilterHelp.getProperty("session_type");
            String cross_domain=SSOClientFilterHelp.getProperty("cross_domain");
            String sso_server_url=SSOClientFilterHelp.getConfigUrl("sso.server.url");
       
            String referer=request.getHeader("Referer");
            //本机ip
            String ssoAppCientIp=addr.getHostAddress().toString();//获得本机IP
            ssoAppCientIp=NetHelp.getLocalHostIp();
            //获得用户Ip
            String userClientIp=NetClientHelp.getIpAddr(request);
            String domain=  NetHelp.getDomainOrIP(request);
            String uri = request.getRequestURI();
            String[] splitAddress=picture_format.split("\\|"); 
        	boolean bls = SSOClientFilterHelp.judgeStaticUrl(uri, splitAddress);
        	boolean isAjax=NetHelp.isAjax(request);
            SSOClientFilterHelp.trace(log, "1.<===============referer:"+referer+"===============>");
    		SSOClientFilterHelp.trace(log, "2.<===============用户ip:::::::"+userClientIp+"===============>");
    		SSOClientFilterHelp.trace(log, "3.<===============用户domain:::::::"+domain+"===============>");
            //是否本都页面登录
            if(sso_client_login_local.equals("true"))//本地登录逻辑
            {
        		SSOClientFilterHelp.trace(log, "4.<===============本地登录逻辑入口===============>");
                boolean is_no_interceptReq=judgenInterceptReq( uri);
                if(bls==true||is_no_interceptReq==true)//直接放行
                {
            		SSOClientFilterHelp.trace(log, "5.<----"+uri+",图片文件直接放行-->");
                    //如果发现是css或者js文件，直接放行
                    filterChain.doFilter(request, response);
                }
                else//需要验证才能放行
                {
                    SSOClientFilterHelp.trace(log, "6.new log befor---------"+request.getRequestURL()+"----"+request.getQueryString()+"-----");
            		String url = "";
                    Factory factory = new SSOSessionFactory();
                    factory.setSession(httpSession);
                    SSOSession session =null;
                    String accountNo="";
                    try{
                     	session = factory.getSSOSession(sessionType); 
                    	accountNo =session.getData(SSOConstants.SESSION_DATA);
                    }
                    catch(Exception e)
                    {
                    	e.printStackTrace();

                    }
                  	//session不为空,已经登录,完全信任,免登录
                	if(null!=accountNo&&!accountNo.equals(""))
                	{
                		url=SSOClientFilterHelp.getReqUrlWithParam(request,false);
                		SSOClientFilterHelp.trace(log, "7.======================session不为空,验证通过======================");
                		filterChain.doFilter(request, response);
                	}
                	else//session为空,同步数据
                	{
                		url=SSOClientFilterHelp.getReqUrlWithParam(request,true);
                    	NetClientHelp nc=new NetClientHelp();
                        String ticket =nc.getTicket(request);// getCookieValue(SSOConstants.SSO_KEY, cookies);

                		SSOClientFilterHelp.trace(log, "8.======================session为空,获得ticket={"+ticket+"}");
                        //ticket不为空
                        if(null!=ticket&&!ticket.equals(""))
                        {
                    		SSOClientFilterHelp.trace(log, "9.---------ticket不为空,获得ticket={"+ticket+"}-----");
                        	String sso_url=sso_sync_ticket_url+"/ticket.do";
                        	String param="token";
                        	
            
                        	String param_value=ticket+","+ssoAppCientIp+","+userClientIp;;
                        	//向sso服务器发送ticket获取userId
                        	
                        	String str=HttpUtil.post(sso_url, param, param_value);
                        	
                        	String[]arr=str.split(",");//post( sso_url, param, param_value);
                            accountNo = arr[0];//post( sso_url, param, param_value);

                        	SSOClientFilterHelp.trace(log, "10.<<<<<<<<<<<<获得userId is::::"+arr[0]+">>>>>>>>>>>>>>");
                            authLocalLoginAccount(filterChain, request, response, session, SSOConstants.SESSION_DATA, accountNo, url,isAjax,"10");

                        }
                        else
                        {
                    		SSOClientFilterHelp.trace(log, "11.---------session为空,ticket为空,向登录页面跳转-----");                
                			checkLocalAjax(request,response, isAjax, url,"11");            		    
                        }
                	}
                	  	
                }
            }
            else//非本地页面登录逻辑
            {
        		SSOClientFilterHelp.trace(log, "12.<===============非本地页面登录逻辑入口==============>");
                if(bls==true)//直接放行
                {
            		SSOClientFilterHelp.trace(log, "13.<----"+uri+",图片文件直接放行-->");
                    //如果发现是css或者js文件，直接放行
                    filterChain.doFilter(request, response);
                }
                else//验证放行
                {
                    boolean bl=false;
                    bl=Boolean.valueOf(cross_domain);
            		SSOClientFilterHelp.trace(log, "14.<===============非本地页面登录逻辑,cross_domain:"+bl+"===============>");
                    Factory factory = new SSOSessionFactory();
                    factory.setSession(httpSession);
                	SSOSession session = factory.getSSOSession(sessionType); 
                	String accountNo =session.getData(SSOConstants.SESSION_DATA);
                	
                	String url = "";
            		if (null != accountNo && !"".equals(accountNo)) 
            		{
            			//url=SSOClientFilterHelp.getReqUrlWithParam(request,false);
            			SSOClientFilterHelp.trace(log, "14.0+<===============非本地页面登录逻辑,session不为空,放行===============>");
            			filterChain.doFilter(request, response);
            		}
            		else
            		{
            			url=SSOClientFilterHelp.getReqUrlWithParam(request,true);
                		SSOClientFilterHelp.trace(log, "15.<===============非本地页面登录逻辑,url:"+url+"===============>");
                		if(null!=referer&&referer.contains(sso_server_url+"/index.do"))//sso服务器第一次返回
                		{
                			SSOClientFilterHelp.trace(log, "15.<===============服务器第一次返回:"+referer+"===============>");
                			String req_ticket=request.getParameter(SSOConstants.TICKET);
                    		noLocal(filterChain, request, response,req_ticket, sso_sync_ticket_url, sso_server_url, ssoAppCientIp,
        							userClientIp, domain, isAjax, bl, session, accountNo, url,"15");
                		}
                		else
                		{
                			SSOClientFilterHelp.trace(log, "16.<===============服务器非第一次返回:"+referer+"===============>");
                			NetClientHelp nc=new NetClientHelp();
                			String cookie=nc.getTicket(request);
                			noLocal(filterChain, request, response,cookie, sso_sync_ticket_url, sso_server_url, ssoAppCientIp,
        							userClientIp, domain, isAjax, bl, session, accountNo, url,"16");
                		}
            		}
            		

                }
            }
        }
        else
        {
        	SSOClientFilterHelp.trace(log, "=====================单点登录未启用=====================");
        	filterChain.doFilter(request, response);
        }
        

    }

	private void noLocal(FilterChain filterChain, HttpServletRequest request, HttpServletResponse response,String req_ticket,
			String sso_sync_ticket_url, String sso_server_url, String ssoAppCientIp, String userClientIp, String domain,
			boolean isAjax, boolean bl, SSOSession session, String accountNo, String url,String lineNum)
					throws IOException, ServletException {
		//String req_ticket=request.getParameter(SSOConstants.TICKET);
		SSOClientFilterHelp.trace(log, lineNum+".1<===============非本地页面登录逻辑,req_ticket:"+req_ticket+"===============>");
		
		if(null!=req_ticket&&!"".equals(req_ticket))
		{
			//第一次登陆成功后回传回来的ticket写入cookie
			if(bl)//跨域
			{
				SSOClientFilterHelp.trace(log,lineNum+".2"+this.getClass().getName()+"---------domain-----"+domain);
				domain = SSOClientFilterHelp.getCookieSetDomain(ssoAppCientIp, domain);
				
				/**
				NetClientHelp nc=new NetClientHelp();
				String cookie=nc.getTicket(request);
				if(null==cookie||"".equals(cookie))
				{
					CookieHelper.addCookie(response, domain, "/", SSOConstants.SSO_COOKIE_KEY,req_ticket, -1);
		    		SSOClientFilterHelp.trace(log,"15.2<---------cookie 创建的   domain::"+domain+"----->");
				}*/
				
				try{
		           	String sso_url=sso_sync_ticket_url+"/ticket.do";
		        	String param="token";
		        	
		        	String param_value=req_ticket+","+ssoAppCientIp+","+userClientIp;;
		        	//向sso服务器发送ticket获取userId
		        	
		        	//String[]arr=post( sso_url, param, param_value);
		        	String str=HttpUtil.post(sso_url, param, param_value);
		        	
		        	String[]arr=str.split(",");//post( sso_url, param, param_value);
		        	
		            accountNo = arr[0];

		            authAccount(filterChain, request, response, session, SSOConstants.SESSION_DATA, accountNo, sso_server_url, url,isAjax,lineNum);
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}

		        
				//filterChain.doFilter(request, response);
			}
			else// 不跨域(非本地页面登录逻辑 )
			{
				SSOClientFilterHelp.trace(log,lineNum+".3=====非本地页面登录逻辑  不跨域===");
				SSOClientFilterHelp.trace(log,this.getClass().getName()+"---------domain-----"+domain);

				try{
		           	String sso_url=sso_sync_ticket_url+"/ticket.do";
		        	String param="token";
		        	
		        	String param_value=req_ticket+","+ssoAppCientIp+","+userClientIp;;
		        	//向sso服务器发送ticket获取userId
		        	
		        	//String[]arr=post( sso_url, param, param_value);
		        	String str=HttpUtil.post(sso_url, param, param_value);
		        	
		        	String[]arr=str.split(",");//post( sso_url, param, param_value);
		        	
		            accountNo = arr[0];

		            authAccount(filterChain, request, response, session, SSOConstants.SESSION_DATA, accountNo, sso_server_url, url,isAjax,lineNum);
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
			}
			
			
		}
		else
		{
		  	//session不为空,已经登录,完全信任,免登录
			if(null!=accountNo&&!accountNo.equals(""))
			{
				SSOClientFilterHelp.trace(log,lineNum+".4.---------session不为空,验证通过-----");
				filterChain.doFilter(request, response);
			}
			else//session为空,同步数据
			{
				
		    	NetClientHelp nc=new NetClientHelp();
		        String ticket =nc.getTicket(request);// getCookieValue(SSOConstants.SSO_KEY, cookies);
				SSOClientFilterHelp.trace(log,lineNum+".5.---------session为空,获得ticket={"+ticket+"}-----");
		        //ticket不为空
		        if(null!=ticket&&!ticket.equals(""))
		        {
		    		SSOClientFilterHelp.trace(log,lineNum+".6.---------ticket不为空,获得ticket={"+ticket+"}-----");
		        	String sso_url=sso_sync_ticket_url+"/ticket.do";
		        	String param="token";
		        	String param_value=ticket+","+ssoAppCientIp+","+userClientIp;;
		        	//向sso服务器发送ticket获取userId
		        	
		        	//String[]arr=post( sso_url, param, param_value);
		        	String str=HttpUtil.post(sso_url, param, param_value);
		        	
		        	String[]arr=str.split(",");//post( sso_url, param, param_value);
		            accountNo = arr[0];//post( sso_url, param, param_value);

		        	SSOClientFilterHelp.trace(log,lineNum+".7.<<<<<<<<<<<<获得userId is::::"+arr[0]+">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
		  
		            authAccount(filterChain, request, response, session, SSOConstants.SESSION_DATA, accountNo, sso_server_url, url,isAjax,"7");

		        }
		        else
		        {
		    		SSOClientFilterHelp.trace(log,lineNum+".8.---------session为空,ticket为空,向登录页面跳转-----");
					String jump_url=sso_server_url+"/index.do?service=" + url;
					checkAjax(request,response, isAjax, jump_url,sso_server_url+"/index.do?service=",lineNum);
				    
		        }
			}
		}
	}

	private void authAccount(FilterChain filterChain, HttpServletRequest request, HttpServletResponse response,
			SSOSession session, String session_data, String accountNo, String sso_server_url, String url,boolean isAjax,String lineNum)
					throws IOException, ServletException {
		if (null != accountNo && !"".equals(accountNo)) 
		{
			SSOClientFilterHelp.trace(log,lineNum+".1.authAccount,从服务端同步数据 "+session_data+":"+accountNo);
            if(null!=accountNo&&!"".equals(accountNo))
            {
                session.setData(SSOConstants.SESSION_DATA,accountNo);
                SSOClientFilterHelp.trace(log,lineNum+".2.authAccount,向session赋值,"+SSOConstants.SESSION_DATA+":"+accountNo);
            }
		    filterChain.doFilter(request, response);
		} 
		else 
		{
			String jump_url=sso_server_url+"/index.do?service=" + url;
			SSOClientFilterHelp.trace(log,lineNum+".3.authAccount,同步数据为空,向服务端重新跳转:"+jump_url);

   			checkAjax(request,response, isAjax, jump_url,sso_server_url+"/index.do?service=",lineNum);
		    
		}
	}

	private void checkAjax(HttpServletRequest request,HttpServletResponse response, boolean isAjax, String jump_url,String sso_server_url,String lineNum) throws IOException {
		//String uri = request.getRequestURI();
		if(isAjax)
		{
	    	try{
				String jumpUrl2=sso_server_url+"/index.do?service=";
				
				String json=
						"{"
						+ "\"jumpUrlAll\":\""+jump_url+"\","
						+ "\"ssoMsg\":\"用户未登录,请先登录!\","
						+ "\"jumpUrl\":\""+jumpUrl2+"\","
						+ "\"ssoCode\":\"111111\""
						+ "}";
				SSOClientFilterHelp.repJson(request, response, json);
	    	}
	    	catch(Exception e)
	    	{
	    		e.printStackTrace();
	    	}
			
	    	SSOClientFilterHelp.trace(log,lineNum+ ".1.checkAjax:::::::::::::::::已经执行response,"+request.getRequestURL()+"::::::::::::::::::::::");
			


		}
		else
		{
			SSOClientFilterHelp.trace(log, "checkAjax.:::::::::非ajax请求:::::::::::::向"+this.getClass().getName()+",向服务端跳转:"+jump_url);
			response.sendRedirect(jump_url);
		}
	}




	
	private boolean judgenInterceptReq(String uri)
	{
		ResourceBundle resource = ResourceBundle.getBundle("sso");
		String  sso_clinet_login_local_req_url=resource.getString("sso_clinet_login_local_req_url");
		String  sso_clinet_login_local_no_intercept_req=resource.getString("sso_clinet_login_local_no_intercept_req");
		boolean is_no_intercept=false;
		if(null!=sso_clinet_login_local_no_intercept_req&&sso_clinet_login_local_no_intercept_req.contains("|"))
		{
			String[] no_intercept_reqs=sso_clinet_login_local_no_intercept_req.split("\\|"); 
			for(String rep:no_intercept_reqs)
			{
				if(uri.contains(rep))
				{
					is_no_intercept=true;
					break;
				}
			}
		}
		else
		{
			if(!"".equals(sso_clinet_login_local_no_intercept_req))
			{
				if(uri.contains(sso_clinet_login_local_no_intercept_req))
				{
					is_no_intercept=true;
				}
			}
		}
		if(is_no_intercept==false)
		{
			if(uri.contains(sso_clinet_login_local_req_url))
			{
				is_no_intercept=true;
			}
		}
		
		return is_no_intercept;
	}
	private void authLocalLoginAccount(FilterChain filterChain, HttpServletRequest request, HttpServletResponse response,
			SSOSession session, String session_data, String accountNo, String url,boolean isAjax,String lineNum)
					throws IOException, ServletException {
		if (null != accountNo && !"".equals(accountNo)) 
		{
			SSOClientFilterHelp.trace(log, lineNum+".1.authLocalLoginAccount==从服务端同步数据 "+session_data+":"+accountNo);
			session.setData(session_data,accountNo);
		    filterChain.doFilter(request, response);
		} 
		else 
		{
			checkLocalAjax(request,response, isAjax, url,lineNum);
		}
	}

	private void checkLocalAjax(HttpServletRequest request,HttpServletResponse response, boolean isAjax, String url,String lineNum) throws IOException {
		if(isAjax)
		{
	    	try{
				String json=
						"{"
						+ "\"jumpUrlAll\":\""+url+"\","
						+ "\"ssoMsg\":\"用户未登录,请先登录!\","
						+ "\"jumpUrl\":\""+url+"\","
						+ "\"ssoCode\":\"111111\""
						+ "}";
				SSOClientFilterHelp.repJson(request, response, json);
	    	}
	    	catch(Exception e)
	    	{
	    		e.printStackTrace();
	    	}
			
	    	SSOClientFilterHelp.trace(log, lineNum+"1.checkLocalAjax===已经执行response,"+request.getRequestURL());
		}
		else
		{
			ResourceBundle resource = ResourceBundle.getBundle("sso");
			String  sso_clinet_login_local_req_url=resource.getString("sso_clinet_login_local_req_url");
			SSOClientFilterHelp.trace(log, "sso_clinet_login_local_req_url.:::本地非ajax请求:::"+this.getClass().getName()+",本地跳转:"+sso_clinet_login_local_req_url);
			try {
		
				String path = request.getContextPath();

				String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
				SSOClientFilterHelp.trace(log, lineNum+"2.checkLocalAjax===本地非ajax请求::::"+this.getClass().getName()+",本地跳转:"+basePath);
				response.sendRedirect(sso_clinet_login_local_req_url);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
    @Override
    public void init(FilterConfig arg0) throws ServletException {

    }

}